// Copyright 2018 Ulf Adams
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Credits:
//
//    1) This work is a heavily modified derivation of the original work by
//       Ulf Adams at URL: https://github.com/ulfjack/ryu.
//       As such, it inherits the Apache license of the original work.
//       Thank you Ulf Adams.
//
//    2) The original java sources were converted to a rough draft of
//       scala code using the service at URL: javatoscala.com.
//
//       The raw conversion did not compile and contained bugs due
//       to the handling of break and return statements, but it saved
//       days, if not weeks, of effort.
//
//       Thank you javatoscala.com.
//
//    3) All additional work, including introduced bugs,  is an original
//       contribution to Scala Native development.

package scala.scalanative
package runtime.ieee754tostring.ryu

object RyuDouble {

  // Scala/Java magic number 24 is derived from original RYU C code magic number 25 (which includes NUL terminator).
  // See https://github.com/ulfjack/ryu/blob/6f85836b6389dce334692829d818cdedb28bfa00/ryu/d2s.c#L506
  final val RESULT_STRING_MAX_LENGTH = 24

  final val DOUBLE_MANTISSA_BITS = 52

  final val DOUBLE_MANTISSA_MASK = (1L << DOUBLE_MANTISSA_BITS) - 1

  final val DOUBLE_EXPONENT_BITS = 11

  final val DOUBLE_EXPONENT_MASK = (1 << DOUBLE_EXPONENT_BITS) - 1

  final val DOUBLE_EXPONENT_BIAS = (1 << (DOUBLE_EXPONENT_BITS - 1)) - 1

  final val POW5_BITCOUNT = 121 // max 3*31 = 124

  final val POW5_INV_BITCOUNT = 122 // max 3*31 = 124

// Tell scalafmt to retain POW5_ARRAY_NCOL column format for human readability.
// format: off

  final val POW5_ARRAY_NCOL = 4

  // Porting note:
  // RyuDouble.java original used runtime initialization for the
  // POW5_SPLIT and POW5_INV_SPLIT arrays.
  //
  // For performance, this file uses equivalent compile time constants.
  // These were generated by the standalone program
  // RyuGenerateConstantsForDouble.scala included as a comment at the
  // bottom of this file.

  final val POW5_SPLIT = scala.Array(
      134217728, 0, 0, 0,
      167772160, 0, 0, 0,
      209715200, 0, 0, 0,
      262144000, 0, 0, 0,
      163840000, 0, 0, 0,
      204800000, 0, 0, 0,
      256000000, 0, 0, 0,
      160000000, 0, 0, 0,
      200000000, 0, 0, 0,
      250000000, 0, 0, 0,
      156250000, 0, 0, 0,
      195312500, 0, 0, 0,
      244140625, 0, 0, 0,
      152587890, 1342177280, 0, 0,
      190734863, 603979776, 0, 0,
      238418579, 218103808, 0, 0,
      149011611, 2015363072, 0, 0,
      186264514, 1982332928, 0, 0,
      232830643, 1404174336, 0, 0,
      145519152, 609173504, 0, 0,
      181898940, 761466880, 0, 0,
      227373675, 951833600, 0, 0,
      142108547, 326460544, 0, 0,
      177635683, 2018688416, 0, 0,
      222044604, 1986489608, 0, 0,
      138777878, 167814181, 0, 0,
      173472347, 1283509550, 536870912, 0,
      216840434, 1067516025, 1744830464, 0,
      135525271, 1204068428, 285212672, 0,
      169406589, 968214623, 356515840, 0,
      211758236, 1747139190, 2056257536, 0,
      264697796, 36440340, 1496580096, 0,
      165436122, 1096517036, 2009104384, 0,
      206795153, 296904472, 363896832, 0,
      258493941, 908001502, 454871040, 0,
      161558713, 835936394, 1894907136, 0,
      201948391, 1581791405, 1294892096, 0,
      252435489, 1440368345, 8002384, 0,
      157772181, 94923847, 1347178770, 0,
      197215226, 655525721, 1147102550, 1073741824,
      246519032, 1893148975, 1970749100, 268435456,
      154074395, 1183218109, 2037024555, 1241513984,
      192592994, 942151725, 935667958, 1015021568,
      240741243, 103947832, 1706455860, 195035136,
      150463276, 1944015587, 1066534912, 1195638784,
      188079096, 282535836, 796297728, 1494548480,
      235098870, 353169795, 995372160, 1868185600,
      146936793, 1831343858, 353672144, 1167616000,
      183670992, 678567086, 1515832004, 1459520000,
      229588740, 848208858, 821048181, 1824400000,
      143492962, 1603872360, 1050026025, 1408685456,
      179366203, 931098626, 1312532532, 150244084,
      224207754, 627002371, 566923841, 187805105,
      140129846, 928747394, 85891944, 1459555470,
      175162308, 87192418, 1181106754, 1824444338,
      218952885, 108990523, 402641619, 1206813598,
      136845553, 336554532, 2130699204, 485823043,
      171056941, 957564078, 515890357, 607278804,
      213821176, 1733826009, 1718604770, 1295969417,
      267276471, 19798864, 537643227, 546219947,
      167047794, 817680658, 336027017, 72952011,
      208809742, 2095842646, 1493775595, 628060925,
      261012178, 1546061484, 793477670, 248205245,
      163132611, 1503159339, 1569665367, 1765741014,
      203915764, 1342078262, 1425210797, 1670305355,
      254894705, 1677597828, 707771673, 477268958,
      159309191, 243192274, 1516099119, 1640470379,
      199136488, 1914603079, 821382075, 1513717062,
      248920611, 245770201, 489856682, 1355275415,
      155575381, 2032654567, 1648337706, 1383918046,
      194469227, 930205473, 1523551221, 656155734,
      243086534, 625885930, 293826290, 1357065580,
      151929083, 2001791442, 720512343, 1385036899,
      189911354, 1965368390, 1974382253, 1194425212,
      237389193, 1382968664, 1394235992, 2029902427,
      148368246, 59049047, 871397495, 1268689017,
      185460307, 1147553133, 552375957, 1048990359,
      231825384, 897570504, 1227340858, 1848108861,
      144890865, 560981565, 767088036, 1691938950,
      181113581, 1238097868, 1495730957, 2114923688,
      226391976, 2084493247, 1869663697, 1033041874,
      141494985, 1302808279, 1973846178, 1987828451,
      176868732, 17897613, 1930436811, 1411043740,
      221085915, 22372017, 802433278, 1226933763,
      138178696, 1893030702, 1843698079, 229962689,
      172723371, 218804730, 1230880774, 1898066098,
      215904213, 1884118649, 464859144, 1298840799,
      134940133, 1446009611, 1632714245, 811775499,
      168675167, 196899278, 1504021894, 1551590286,
      210843958, 1856736834, 806285544, 865746033,
      263554948, 1247179218, 2081598754, 1082182542,
      164721842, 1853228835, 1837870133, 1213235000,
      205902303, 1242794220, 1760466754, 2053414663,
      257377879, 1016621864, 53099795, 1493026504,
      160861174, 1440695033, 33187372, 664706109,
      201076468, 727126967, 578355127, 830882636,
      251345585, 908908709, 186072997, 501732384,
      157090990, 1910245223, 384731079, 582018196,
      196363738, 1314064704, 2091526585, 190651833,
      245454673, 568839057, 466924583, 775185703,
      153409170, 1697701690, 1634005144, 1289797432,
      191761463, 1048385289, 968764606, 1612246790,
      239701829, 773610699, 1747826670, 941566664,
      149813643, 751942143, 823956213, 51608253,
      187267054, 403056767, 493074354, 601381228,
      234083817, 1577562783, 79472030, 1825468359,
      146302386, 180670371, 854976387, 604046812,
      182877982, 1299579788, 531849572, 218187604,
      228597478, 550732911, 664811965, 272734505,
      142873423, 1954820805, 1220813846, 438894521,
      178591779, 1906655094, 2062888219, 1622359976,
      223239724, 1846447956, 1504868450, 1491079058,
      139524828, 80288148, 2014284605, 1468795323,
      174406035, 100360186, 370372109, 225381418,
      218007543, 1736062968, 1536706960, 818597684,
      136254714, 1890345723, 960441850, 511623552,
      170318393, 1289190330, 663681400, 1713271265,
      212897992, 875176, 1903343574, 2141589081,
      266122490, 1093971, 231695820, 1603244527,
      166326556, 537554643, 2023858079, 2075769653,
      207908195, 671943304, 1992951687, 2057841155,
      259885244, 303058219, 343705961, 2035430532,
      162428277, 1263153210, 2093864418, 466837714,
      203035346, 2115812425, 1543588698, 1657288967,
      253794183, 1571023708, 318873137, 997869385,
      158621364, 1787196185, 1273037534, 1965845645,
      198276706, 86511583, 2128167830, 1383565233,
      247845882, 1181881303, 2123338876, 655714717,
      154903676, 1275546726, 2132393165, 1483563522,
      193629595, 1594433408, 1591749633, 243841667,
      242036994, 1456170848, 1989687041, 841672995,
      151273121, 1446977692, 1243554400, 1868222902,
      189091402, 198109379, 1554443001, 187794979,
      236364252, 1321378548, 1406182839, 771614636,
      147727657, 1899603416, 1952606098, 1287565516,
      184659572, 763891535, 293273975, 535715071,
      230824465, 954864418, 1977205205, 132772926,
      144265290, 1938967541, 1772624165, 351418535,
      180331613, 1349967603, 605167470, 976144081,
      225414517, 76846768, 219588426, 146438277,
      140884073, 316464686, 137242766, 628394835,
      176105091, 932451769, 1245295281, 1859235368,
      220131364, 628693799, 2093490014, 713431474,
      137582102, 1466675448, 2113737626, 2056507407,
      171977628, 759602487, 494688385, 1496892435,
      214972035, 949503109, 81489570, 260502808,
      134357522, 325003987, 319366437, 699685167,
      167946902, 1479996807, 2009820782, 1411477370,
      209933628, 776254185, 1975405066, 690604889,
      262417035, 970317732, 858643596, 1936997935,
      164010647, 338013126, 1610394072, 136881885,
      205013308, 2033129144, 939250766, 171102357,
      256266636, 393927782, 1174063457, 1287619770,
      160166647, 1319946688, 196918748, 2146939636,
      200208309, 1113062448, 246148436, 536190897,
      250260386, 1928198972, 307685545, 670238622,
      156412741, 1741995269, 1266045289, 1761076419,
      195515927, 566881350, 2119427524, 590732787,
      244394909, 171730776, 1575542581, 738415984,
      152746818, 375767191, 984714113, 729945446,
      190933522, 1543450813, 694021729, 1449302720,
      238666903, 855571692, 1404398074, 201015664,
      149166814, 1340038675, 1951490620, 662505702,
      186458518, 601306520, 1902492363, 828132127,
      233073147, 1825374975, 230631806, 498294247,
      145670717, 872423903, 949451246, 1922046640,
      182088396, 1627400791, 649943146, 1328816476,
      227610495, 2034250989, 275558021, 587278772,
      142256559, 2076713236, 440659219, 635484688,
      177820699, 2059020633, 550824024, 257484948,
      222275874, 2036904879, 1225400942, 321856185,
      138922421, 1809936461, 1571181956, 1811772852,
      173653027, 651807841, 353364710, 117232417,
      217066284, 277888889, 978576799, 1220282345,
      135666427, 1247422379, 1953787779, 1567982833,
      169583034, 1022407062, 1905363812, 1423107630,
      211978793, 204267004, 1307962941, 1778884537,
      264973491, 792204667, 1634953677, 612992936,
      165608432, 226692461, 753410592, 651556041,
      207010540, 283365576, 1478634152, 814445051,
      258763175, 354206970, 1848292690, 1018056314,
      161726984, 1026685724, 1692053843, 1173156108,
      202158730, 1283357155, 2115067304, 929574223,
      252698413, 530454620, 2106963218, 1161967779,
      157936508, 599969594, 243110187, 1263100774,
      197420635, 749961992, 1377629558, 1042005055,
      246775794, 400581578, 1722036948, 228764495,
      154234871, 787234398, 1613144004, 1216719633,
      192793589, 447172086, 942688181, 1520899542,
      240991986, 1095836020, 104618403, 290511691,
      150619991, 1221768424, 1139128325, 2060617999,
      188274989, 990339618, 1423910407, 965159763,
      235343736, 1774795435, 706146185, 669578792,
      147089835, 1109247147, 172905909, 1760664025,
      183862294, 849688021, 1826745123, 590217295,
      229827867, 2135851851, 672818668, 200900707,
      143642417, 1066471951, 152076211, 1199304766,
      179553021, 1869960850, 1800708000, 962260045,
      224441277, 726838327, 1177143176, 1202825056,
      140275798, 722709410, 1541020853, 751765660,
      175344747, 1977128587, 852534242, 1476577987,
      219180934, 1934539822, 528796891, 771980660,
      136988084, 672216476, 1941110793, 214052456,
      171235105, 840270596, 278904843, 804436483,
      214043881, 1587209157, 348631054, 468674691,
      267554852, 373398710, 972659729, 1659585188,
      167221782, 1307116018, 71041419, 231934375,
      209027228, 560153198, 1162543597, 1900530704,
      261284035, 700191498, 379437673, 765050645,
      163302522, 169184230, 774019457, 1820333933,
      204128152, 1285222111, 2041266146, 664804680,
      255160190, 1606527639, 2014711770, 1904747674,
      159475119, 467208862, 2064501224, 1727338208,
      199343899, 47140166, 1506884707, 11689112,
      249179873, 1669537944, 809864059, 1625224126,
      155737421, 238154847, 506165037, 747329623,
      194671776, 834564471, 95835384, 1471032941,
      243339720, 1043205588, 1730406966, 1838791176,
      152087325, 652003493, 7762530, 612373573,
      190109156, 1351875278, 546574074, 1839208790,
      237636445, 1689844097, 1756959417, 1225269164,
      148522778, 1324588017, 292793267, 2107970507,
      185653473, 581993197, 902862496, 2098092222,
      232066841, 1264362408, 1665449033, 475131630,
      145041775, 2132403785, 1040905645, 1639134548,
      181302219, 2128633819, 1838002969, 438305450,
      226627774, 2123921362, 1760632799, 1084752724,
      141642359, 790579939, 1637266411, 1483276820,
      177052949, 451354012, 1509712102, 1317225114,
      221316186, 1101063427, 1887140128, 572789568,
      138322616, 1225035554, 911027124, 357993480,
      172903270, 1531294443, 65042081, 447491850,
      216129088, 840376229, 1691915337, 1096235725,
      135080680, 525235143, 1325882541, 2027324608,
      168850850, 656543929, 1120482265, 923543024,
      211063562, 1894421735, 1937473743, 1691299692,
      263829453, 1294285345, 1884971267, 1577253703,
      164893408, 1077363797, 372800674, 717348108,
      206116760, 1346704746, 1002871754, 1970426959,
      257645950, 1683380933, 179847869, 1389291875,
      161028719, 515242171, 380840374, 1136742878,
      201285899, 107181801, 2086663204, 347186773,
      251607373, 1744589988, 997716269, 433983467,
      157254608, 1358804198, 1697314492, 539675123,
      196568260, 1698505248, 1047901291, 674593903,
      245710325, 2123131560, 1309876614, 306371467,
      153568953, 1595392681, 818672883, 1802094903,
      191961192, 383628115, 1560212016, 1715747717,
      239951490, 479535144, 1413394108, 2144684646,
      149969681, 836580377, 883371318, 266686080,
      187462101, 1582596383, 1641085059, 1407099424,
      234327627, 367632743, 1514485412, 1222003368,
      146454766, 2108818656, 1751859750, 1837493929,
      183068458, 1562281497, 42341040, 1223125587,
      228835573, 879110047, 589797212, 1528906984,
      143022233, 817879235, 1173929625, 2029308689,
      178777791, 1559219956, 930541120, 926023125,
      223472239, 1412154033, 1163176400, 1157528906,
      139670149, 1687902638, 2069162530, 723455566,
      174587687, 499265562, 1512711338, 1978061282,
      218234609, 87211041, 817147349, 1398834779,
      136396630, 1396684180, 1852894373, 1142707192,
      170495788, 672113402, 168634318, 1965254903,
      213119735, 840141752, 1284534722, 1382826804,
      266399669, 513306278, 1605668403, 654791682,
      166499793, 589251880, 466671840, 140809345,
      208124741, 1273435762, 583339800, 176011681,
      260155926, 2128665614, 1802916574, 220014602,
      162597454, 793545097, 589951946, 1748121862,
      203246817, 2065673195, 1274310845, 1111410503,
      254058522, 971478758, 1056017644, 1926134041,
      158786576, 1144045136, 123140116, 130091952,
      198483220, 1430056420, 153925145, 162614940,
      248104025, 1787570525, 192406431, 740139587,
      155065016, 311925210, 388689475, 1267893610,
      193831270, 389906512, 1559603668, 1047996100,
      242289087, 1561124964, 1949504585, 1309995125,
      151430679, 1781009471, 144698542, 13440585,
      189288349, 1689390926, 1791485913, 1090542555,
      236610437, 501125922, 1165615567, 1900049106,
      147881523, 581639157, 1265380641, 1992837059,
      184851904, 190178034, 2118596714, 880433588,
      231064880, 237722543, 1574504069, 26800161,
      144415550, 148576589, 1789371411, 285185557,
      180519437, 1259462561, 626101527, 1967094682,
      225649296, 2111199113, 1319497821, 1921997441,
      141030810, 1319499446, 19379770, 1469683856,
      176288513, 575632483, 1097966537, 763362996,
      220360641, 1256411516, 835587259, 1491074658,
      137725400, 2127434477, 1595983861, 663486205,
      172156751, 511809449, 384367090, 1366228668,
      215195939, 102890899, 1017329775, 634044011,
      134497461, 1943355004, 367395653, 1201583875,
      168121827, 818581019, 459244566, 2038850756,
      210152284, 486355362, 37184796, 1474821621,
      262690355, 607944202, 1120222819, 1843527026,
      164181472, 111529670, 1237010174, 883768935,
      205226840, 139412088, 472520894, 30969345,
      256533550, 174265110, 590651117, 1112453505,
      160333468, 1719528429, 1979769684, 963718897,
      200416836, 1926889, 864099369, 1204648621,
      250521045, 2408611, 1616995123, 2042681688,
      156575653, 269940838, 742186496, 1008240599,
      195719566, 874296959, 2001474944, 1260300749,
      244649458, 19129375, 1964972768, 1575375936,
      152905911, 548826771, 2033414348, 984609960,
      191132389, 149162552, 2004897023, 1230762450,
      238915486, 723324103, 358637631, 1001582151,
      149322178, 2062690300, 1029454887, 1431295212,
      186652723, 1504621051, 1286818609, 1252248103,
      233315904, 1343905402, 1071652349, 2102181041,
      145822440, 839940876, 1206653630, 1582298607,
      182278050, 1049926095, 1508317038, 904131434,
      227847563, 238665795, 1348525386, 56422469,
      142404726, 2028214314, 574392910, 572134955,
      178005908, 1461526068, 1791732961, 1788910518,
      222507385, 1826907586, 92182554, 625525411,
      139067116, 336510873, 594485008, 927824294,
      173833895, 420638591, 1279977172, 1159780368,
      217292368, 2136410975, 1063100553, 1449725460,
      135807730, 1335256859, 1469744214, 100772044,
      169759663, 595329250, 1300309355, 1199706879,
      212199579, 207290651, 551644870, 962762687,
      265249473, 1869726050, 152685176, 129711535,
      165780921, 363272413, 632299147, 81069709,
      207226151, 990961428, 1327244845, 1711949873
    )

  // See porting note just above POW5_SPLIT array above.

  final val POW5_INV_SPLIT = scala.Array(
      536870912, 0, 0, 1,
      429496729, 1288490188, 1717986918, 858993460,
      343597383, 1460288880, 1374389534, 1546188227,
      274877906, 2027224563, 1529008357, 807453852,
      439804651, 237082194, 1587419912, 1291926163,
      351843720, 1907652674, 410942470, 1892534390,
      281474976, 1526122139, 758250706, 655034053,
      450359962, 1582801963, 1642697859, 1477551214,
      360287970, 407248111, 1743655017, 752544241,
      288230376, 325798489, 965427284, 602035393,
      461168601, 1809767771, 1974180384, 963256629,
      368934881, 1018317487, 2008841037, 341108574,
      295147905, 385157260, 1607072829, 1561377048,
      472236648, 616251617, 423832879, 1209713087,
      377789318, 1351994752, 2057053222, 108777011,
      302231454, 1940589261, 1216145848, 87021609,
      483570327, 1816452629, 1516336627, 568731303,
      386856262, 594168644, 1213069301, 1743475232,
      309485009, 1763825104, 970455441, 965283456,
      495176015, 1533629978, 693735247, 255963340,
      396140812, 1226903982, 1413981656, 1922757591,
      316912650, 122529726, 1990178784, 1538206073,
      507060240, 196047563, 177808948, 743142797,
      405648192, 156838050, 1001240617, 1883004427,
      324518553, 1413960629, 371495764, 1506403542,
      519229685, 1832840277, 164896493, 1980748937,
      415383748, 1466272221, 1420407383, 2014095879,
      332306998, 2032011236, 1136325907, 322786514,
      531691198, 674237600, 1818121451, 945955152,
      425352958, 1398383539, 1883993890, 1615757581,
      340282366, 1977700291, 218704923, 1722102795,
      272225893, 1152663503, 604460668, 1377682236,
      435561429, 1414764875, 1396633799, 915801388,
      348449143, 1561308630, 258313580, 732641111,
      278759314, 2108040363, 636147593, 1874603077,
      446014903, 2084374392, 1017836150, 422384546,
      356811923, 379009325, 384772190, 1196901096,
      285449538, 1162200919, 737314482, 98527418,
      456719261, 1430024741, 750206441, 1446134057,
      365375409, 714523063, 1029661882, 2015900705,
      292300327, 1001115180, 823729506, 753727105,
      467680523, 2031281018, 458973750, 2064956827,
      374144419, 336534625, 1655669189, 1222468732,
      299315535, 698724430, 465541892, 977974986,
      478904856, 1117959088, 744867027, 1994256706,
      383123885, 464870541, 166396892, 1595405365,
      306499108, 371896432, 1851104432, 1276324292,
      490398573, 165537562, 2102773632, 2042118867,
      392318858, 991423509, 1252722176, 1633695094,
      313855086, 1652132266, 1861171200, 1306956075,
      502168138, 1784418167, 1689383732, 373142802,
      401734511, 139044345, 922010256, 298514241,
      321387608, 1829222394, 1596601664, 238811393,
      514220174, 349775453, 2125065932, 2100085147,
      411376139, 709317092, 1700052746, 821074659,
      329100911, 996950403, 1789538926, 1515853186,
      526561458, 736127186, 2004268823, 1136874909,
      421249166, 1447895208, 1603415058, 1768493386,
      336999333, 728819437, 853235317, 985297980,
      269599466, 1442049009, 253091524, 788238384,
      431359146, 1448284955, 834443168, 1261181414,
      345087317, 729131234, 1526547994, 149951672,
      276069853, 1871795176, 1221238395, 549458067,
      441711766, 417891904, 1953981432, 879132907,
      353369412, 2052300442, 704191686, 1562299785,
      282695530, 782846894, 1422346808, 1249839828,
      452312848, 1252555031, 987264704, 1999743725,
      361850278, 1861037484, 789811763, 2029291709,
      289480223, 200339798, 1490842870, 764439908,
      463168356, 2038530596, 667361674, 364110394,
      370534685, 1201327747, 963386068, 2009275234,
      296427748, 961062197, 2059199043, 2036916917,
      474284397, 1108202787, 288241363, 252589959,
      379427518, 27568770, 1089586549, 1490562156,
      303542014, 881048475, 1301165969, 762952996,
      485667223, 121187372, 363878632, 1220724793,
      388533778, 955943356, 2009089824, 976579834,
      310827022, 1623748144, 1607271859, 1210760597,
      497323236, 880010113, 424151327, 648726766,
      397858589, 274511360, 2057307980, 518981413,
      318286871, 649105818, 786852924, 2133172049,
      509258994, 179575850, 399971220, 1695088360,
      407407195, 573157409, 1608467165, 926573958,
      325925756, 458525927, 1716270461, 2029749355,
      521481209, 2022131673, 598549091, 241121861,
      417184967, 2047202068, 478839272, 1910884407,
      333747974, 778768195, 812568147, 1958204256,
      533996758, 2105022571, 1729605766, 556146431,
      427197407, 395527868, 1383684613, 15420415,
      341757925, 1604912483, 1536444420, 12336332,
      273406340, 1283929986, 2088148995, 439365796,
      437450144, 2054287979, 334561285, 273488543,
      349960115, 2072927112, 1985635946, 1077784294,
      279968092, 1658341690, 729515298, 3233976,
      447948948, 935359786, 308231017, 1293664550,
      358359158, 1607281288, 246584814, 175938181,
      286687326, 2144818489, 1485758040, 140750545,
      458699723, 425232476, 659225945, 1513691060,
      366959778, 1199179440, 527380756, 1210952848,
      293567822, 1818337011, 851401334, 1827755738,
      469708516, 1191352299, 1791738865, 776925532,
      375766813, 523585110, 574397633, 192043696,
      300613450, 1277861547, 889014836, 153634957,
      480981520, 2044578475, 1851920467, 675312661,
      384785216, 1635662780, 1481536373, 1828740318,
      307828173, 879033494, 2044222558, 603998795,
      492525077, 976956862, 693775715, 1395894801,
      394020061, 2070055678, 1414014031, 1546212571,
      315216049, 1226547813, 701714495, 1666466786,
      504345679, 673986312, 1122743193, 518863210,
      403476543, 968685779, 1327691284, 415090568,
      322781234, 1633942082, 1921146486, 1191065914,
      516449975, 1325817143, 1785344189, 1476208732,
      413159980, 1060653715, 139785162, 2039960445,
      330527984, 848522972, 111828130, 772974897,
      528844775, 69146566, 1037918467, 1666256564,
      423075820, 55317253, 400838044, 1333005251,
      338460656, 44253802, 1179663894, 1925397660,
      270768524, 1753389960, 943731115, 1969814858,
      433229639, 1516933747, 1939466515, 145226665,
      346583711, 1643043727, 1981069941, 1404671521,
      277266969, 884938252, 1584855953, 694240487,
      443627151, 127411015, 1247279336, 1110784780,
      354901720, 1819915730, 1856816928, 888627824,
      283921376, 1455932584, 1485453542, 1569895718,
      454274202, 1470498676, 658738749, 2082336419,
      363419362, 317405481, 1815481188, 1665869136,
      290735489, 1542414574, 593391491, 1762192038,
      465176783, 1179373130, 90432927, 1531017072,
      372141426, 1802491963, 501843071, 1654310387,
      297713141, 1012496840, 2119461375, 1752945040,
      476341026, 761001486, 814157823, 1516221874,
      381072821, 179304459, 1080822988, 1212977499,
      304858256, 1861430486, 5664931, 1399878729,
      487773210, 2119295318, 868057349, 1810309237,
      390218568, 1695436254, 1553439339, 159757201,
      312174855, 67858814, 2101744930, 986799220,
      499479768, 108574103, 2074301699, 2008375481,
      399583814, 945852742, 800447900, 1606700385,
      319667051, 1186178923, 1069855050, 426366849,
      511467282, 1038892818, 852774621, 252690228,
      409173825, 2119604443, 1111716426, 1061145642,
      327339060, 1695683554, 1748366600, 848916514,
      523742497, 565610039, 1508896371, 1787763151,
      418993997, 1740978220, 1207117097, 1000713792,
      335195198, 533789117, 536196948, 800571033,
      536312317, 424565857, 2146405306, 421920194,
      429049853, 1628142875, 428634056, 337536155,
      343239883, 14024111, 772403974, 1129022383,
      274591906, 870212748, 617923179, 1332714636,
      439347050, 533346938, 129683628, 414356500,
      351477640, 426677550, 962740361, 1619975389,
      281182112, 341342040, 770192289, 866483581,
      449891379, 975643994, 373314203, 1815870459,
      359913103, 1210011924, 2016638281, 1023199638,
      287930482, 1827002999, 324820436, 818559711,
      460688772, 1205217880, 519712698, 450702077,
      368551018, 105180844, 2133757076, 2078548580,
      294840814, 943138135, 418515472, 1662838864,
      471745303, 220530827, 1099121486, 83561805,
      377396242, 1035418121, 449800459, 496346174,
      301916993, 2116824685, 1648330556, 397076939,
      483067190, 809939119, 1348838701, 205826373,
      386453752, 647951295, 1508567690, 1023654558,
      309163001, 1806851225, 777357422, 1677917105,
      494660802, 2031968501, 814275146, 1825673909,
      395728642, 766581341, 1939910306, 601545668,
      316582913, 1901755262, 692934785, 1769726723,
      506532662, 465828042, 249702198, 254582380,
      405226129, 1661152622, 1058755217, 1492156093,
      324180903, 1758418827, 1276500903, 1623221604,
      518689446, 236489746, 1183407986, 1738161106,
      414951556, 1907178715, 1376223119, 102038696,
      331961245, 1096246242, 1959971954, 940624416,
      531137992, 1753993988, 1417968208, 1504999066,
      424910394, 544201731, 1563871296, 1203999253,
      339928315, 864858114, 2110090496, 963199402,
      271942652, 691886491, 2117569126, 1629552981,
      435108243, 1536515116, 1670123684, 889297851,
      348086594, 2088205552, 1336098947, 1140935011,
      278469275, 2100061171, 1498375887, 1342244738,
      445550841, 1212614226, 1538407961, 107933,
      356440673, 540594651, 1660223098, 859079806,
      285152538, 1291469180, 1328178478, 1546257304,
      456244061, 1636853959, 836595377, 326528038,
      364995249, 879986437, 1957766490, 1120215890,
      291996199, 1133485879, 1995709922, 37179253,
      467193919, 525087219, 186658768, 59486804,
      373755135, 849566504, 1867313932, 1765576362,
      299004108, 679653203, 1923347875, 1841957819,
      478406573, 657948396, 1359369682, 2088139051,
      382725258, 1385352176, 1087495746, 811517782,
      306180206, 1967275200, 869996597, 219717496,
      489888331, 141163213, 962497825, 1640038182,
      391910664, 1830917489, 340501531, 23540357,
      313528531, 1894230720, 1990388143, 448329015,
      501645651, 24292046, 607640651, 1146823153,
      401316520, 1737420555, 915609250, 1776451982,
      321053216, 1389936444, 732487400, 1421161586,
      513685146, 1364904851, 1601476570, 1414865078,
      410948117, 662427151, 1710677986, 272898603,
      328758493, 1818431910, 509548929, 1506809071,
      526013590, 332510678, 1674271746, 1551901055,
      420810872, 266008543, 50927208, 1241520844,
      336648697, 1501297023, 470238496, 993216675,
      269318958, 342044159, 805687526, 1653566799,
      430910333, 117773925, 859603313, 498223231,
      344728266, 953212599, 1117179380, 398578585,
      275782613, 333073350, 34750044, 2036849786,
      441252181, 103420630, 914593531, 252482550,
      353001744, 1800723422, 1590668284, 201986040,
      282401395, 1870075467, 1702031356, 1879575751,
      451842233, 844637100, 1005263252, 1289334283,
      361473786, 1534703139, 1233707331, 1460964156,
      289179029, 798265782, 127972406, 309777866,
      462686446, 2136218710, 1063749309, 66147855,
      370149157, 1279478238, 1709992906, 911911743,
      296119326, 164589131, 1797491054, 1588522854,
      473790921, 1551832799, 1587495498, 1682643107,
      379032737, 811969510, 411002939, 1775611215,
      303226189, 1938065796, 2046789270, 561495513,
      485161903, 1812415086, 697882454, 1757386280,
      388129523, 161441880, 558305963, 1835405753,
      310503618, 988146963, 876141500, 1468324603,
      496805789, 1151538411, 1831323130, 1490325905,
      397444631, 1350727459, 176568315, 1621757454,
      317955705, 651085237, 1429744841, 867909234,
      508729128, 1041736380, 569604827, 1818151503,
      406983302, 1692382563, 885180591, 1884017932,
      325586642, 494912591, 1137641203, 218724157,
      520938627, 1221356876, 102239006, 1208952110,
      416750902, 118092041, 1370281394, 108168229,
      333400721, 1382963822, 237231656, 86534583,
      533441154, 1353748656, 379570649, 1426945522,
      426752923, 1512495654, 1162649978, 2000549877,
      341402338, 2068989982, 1789113442, 741446442,
      273121871, 366701797, 1001794024, 593157154,
      436994993, 1875213064, 1602870438, 1808044905,
      349595995, 211680262, 2141289810, 587442465,
      279676796, 169344210, 854038389, 40457242,
      447482873, 1559440925, 936964692, 1782718506,
      357986298, 2106546199, 1179068483, 1855671535,
      286389039, 396746770, 1802248246, 625543769,
      458222462, 1493788292, 1165610275, 1430366759,
      366577970, 336037174, 1791481679, 1573790137,
      293262376, 268829739, 1862682073, 829535380,
      469219801, 1718617772, 1262304399, 38766419,
      375375841, 945397488, 1009843519, 460509865,
      300300673, 326821261, 378378085, 1656898081,
      480481077, 93417288, 605404937, 503553281,
      384384861, 1363224019, 913820679, 832339354,
      307507889, 661082485, 2019546732, 665871484,
      492012622, 1916725436, 1513287853, 635897644,
      393610098, 674386890, 351636823, 938214845,
      314888078, 1398502971, 710806188, 750571876,
      503820925, 1808108024, 1137289901, 771418272,
      403056740, 1446486419, 1339328650, 1476128077,
      322445392, 1157189135, 1500959650, 321909002,
      515912628, 133515698, 1542541981, 85557674,
      412730102, 965806018, 375040125, 1356936328,
      330184081, 2061135003, 729528830, 226555603,
      528294531, 291338898, 308252668, 2080475883,
      422635624, 1951058036, 1964589053, 1234883977,
      338108499, 1990343159, 283181054, 128913723,
      270486799, 2021771256, 1944531761, 1391621167,
      432778879, 1946343822, 534270441, 79110219,
      346223103, 1986571787, 856913082, 922281634,
      276978483, 300767241, 256033736, 737825308,
      443165573, 51730856, 409653978, 321527033,
      354532458, 900378144, 327723182, 1116215085,
      283625966, 1579295974, 1121172005, 463475339,
      453801546, 1667880100, 75888289, 2030050731,
      363041237, 904807350, 919704091, 335550396,
      290432989, 2012336069, 306266543, 697937046,
      464692783, 1931247521, 1778516658, 257705815,
      371754227, 256507828, 1422813326, 1065158111,
      297403381, 1493696451, 1567747390, 1711119948,
      475845410, 1530920863, 1219905636, 1019804998,
      380676328, 1224736690, 1834917968, 815843999,
      304541062, 1838782811, 1897431104, 652675199,
      487265700, 1224065580, 1317902848, 1044280318,
      389812560, 979252464, 1054322278, 1694417714,
      311850048, 783401971, 1272954552, 1355534171,
      498960077, 823946424, 2036727284, 450867755,
      399168061, 1947647328, 1629381827, 790190934,
      319334449, 1128621133, 874008732, 632152747,
      510935119, 517303624, 1398413971, 1440941125,
      408748095, 843339629, 689234447, 1582249629,
      326998476, 674671703, 980884287, 1695296433,
      523197562, 220481266, 710421401, 564990645,
      418558049, 1464875201, 1856827309, 1740482705
    )

  // format: on

  @inline
  private def copyLiteralToCharArray(
      literal: String,
      literalLength: Int,
      result: scala.Array[Char],
      offset: Int
  ): Int = {
    literal.getChars(0, literalLength, result, offset)
    offset + literalLength
  }

  // See: https://github.com/scala-native/scala-native/issues/2902
  /** Low-level function executing the Ryu algorithm on `Double` value. This
   *  function allows destination passing style. This means that the result
   *  destination (`Array[Char]`) has to be passed as an argument. The goal is
   *  to avoid additional allocations when possible. Warnings: this function
   *  makes no verification of destination bounds (offset and length are assumed
   *  to be valid). The caller must thus ensure that `result.length - offset >=
   *  RESULT_STRING_MAX_LENGTH`.
   *
   *  @param value
   *    the value to be converted
   *  @param roundingMode
   *    customization of Ryu rounding mode
   *  @param result
   *    the `Array[Char]` destination of the conversion result
   *  @param offset
   *    index in `Array[Char]` destination where new chars will start to be
   *    written
   *  @return
   *    new offset as: old offset + number of created chars (i.e. last modified
   *    index + 1)
   */
  def doubleToChars(
      value: Double,
      roundingMode: RyuRoundingMode,
      result: scala.Array[Char],
      offset: Int
  ): Int = {

    // Handle all the trivial cases.
    if (value.isNaN())
      return copyLiteralToCharArray("NaN", 3, result, offset)
    if (value == Double.PositiveInfinity)
      return copyLiteralToCharArray("Infinity", 8, result, offset)
    if (value == Double.NegativeInfinity)
      return copyLiteralToCharArray("-Infinity", 9, result, offset)

    val bits = java.lang.Double.doubleToLongBits(value)
    if (bits == 0)
      return copyLiteralToCharArray("0.0", 3, result, offset)
    if (bits == 0x8000000000000000L)
      return copyLiteralToCharArray("-0.0", 4, result, offset)

    // Otherwise extract the mantissa and exponent bits and run the full algorithm.
    // Step 1: Decode the floating point number, and unify normalized and subnormal cases.
    val ieeeExponent =
      ((bits >>> DOUBLE_MANTISSA_BITS) & DOUBLE_EXPONENT_MASK).toInt
    val ieeeMantissa = bits & DOUBLE_MANTISSA_MASK

    // By default, the correct mantissa starts with a 1, except for denormal numbers.
    var e2 = 0
    var m2 = 0L
    if (ieeeExponent == 0) {
      // Denormal number - no implicit leading 1, and the exponent is 1, not 0.
      e2 = 1 - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS
      m2 = ieeeMantissa
    } else {
      // Add implicit leading 1.
      e2 = ieeeExponent - DOUBLE_EXPONENT_BIAS - DOUBLE_MANTISSA_BITS
      m2 = ieeeMantissa | (1L << DOUBLE_MANTISSA_BITS)
    }
    val sign = bits < 0

    // Step 2: Determine the interval of legal decimal representations.
    val even = (m2 & 1) == 0
    val mv = 4 * m2
    val mp = 4 * m2 + 2
    val mmShift =
      if ((m2 != (1L << DOUBLE_MANTISSA_BITS)) || (ieeeExponent <= 1)) 1
      else 0
    val mm = 4 * m2 - 1 - mmShift
    e2 -= 2

    // Step 3: Convert to a decimal power base using 128-bit arithmetic.
    // -1077 = 1 - 1023 - 53 - 2 <= e_2 - 2 <= 2046 - 1023 - 53 - 2 = 968
    var dv = 0L
    var dp = 0L
    var dm = 0L
    var e10 = 0
    var dmIsTrailingZeros = false
    var dvIsTrailingZeros = false
    if (e2 >= 0) {

      val q = Math.max(0, ((e2 * 78913) >>> 18) - 1)
      // k = constant + floor(log_2(5^q))
      val k = POW5_INV_BITCOUNT + pow5bits(q) - 1
      val i = -e2 + q + k
      dv = mulPow5InvDivPow2(mv, q, i)
      dp = mulPow5InvDivPow2(mp, q, i)
      dm = mulPow5InvDivPow2(mm, q, i)
      e10 = q
      if (q <= 21) {
        if (mv % 5 == 0) {
          dvIsTrailingZeros = multipleOfPowerOf5(mv, q)
        } else if (roundingMode.acceptUpperBound(even)) {
          dmIsTrailingZeros = multipleOfPowerOf5(mm, q)
        } else if (multipleOfPowerOf5(mp, q)) {
          dp -= 1
        }
      }
    } else {
      val q = Math.max(0, ((-e2 * 732923) >>> 20) - 1)
      val i = -e2 - q
      val k = pow5bits(i) - POW5_BITCOUNT
      val j = q - k
      dv = mulPow5divPow2(mv, i, j)
      dp = mulPow5divPow2(mp, i, j)
      dm = mulPow5divPow2(mm, i, j)
      e10 = q + e2

      if (q <= 1) {
        dvIsTrailingZeros = true
        if (roundingMode.acceptUpperBound(even)) {
          dmIsTrailingZeros = mmShift == 1
        } else {
          dp -= 1
        }
      } else if (q < 63) {
        dvIsTrailingZeros = (mv & ((1L << (q - 1)) - 1)) == 0
      }
    }

    // Step 4: Find the shortest decimal representation in the interval of legal representations.
    //
    // We do some extra work here in order to follow Float/Double.toString
    // semantics. In particular, that requires printing in scientific format
    // if and only if the exponent is between -3 and 7, and it requires
    // printing at least two decimal digits.
    //
    // Above, we moved the decimal dot all the way to the right, so now we need to count digits
    // to figure out the correct exponent for scientific notation.
    val vplength = decimalLength(dp)
    var exp = e10 + vplength - 1
    // Double.toString semantics requires using scientific notation if and only if outside this range.
    val scientificNotation = !((exp >= -3) && (exp < 7))
    var removed = 0
    var lastRemovedDigit = 0
    var output = 0L
    if (dmIsTrailingZeros || dvIsTrailingZeros) {
      var done = false // workaround break in .java source
      while ((dp / 10 > dm / 10) && !done) {
        if ((dp < 100) && scientificNotation) {
          // Double.toString semantics requires printing at least two digits.
          done = true
        } else {
          dmIsTrailingZeros &= dm % 10 == 0
          dvIsTrailingZeros &= lastRemovedDigit == 0
          lastRemovedDigit = (dv % 10).toInt
          dp /= 10
          dv /= 10
          dm /= 10
          removed += 1
        }
      }
      if (dmIsTrailingZeros && roundingMode.acceptLowerBound(even)) {
        var done = false // workaround break in .java source
        while ((dm % 10 == 0) && !done) {
          if ((dp < 100) && scientificNotation) {
            // Double.toString semantics requires printing at least two digits.
            done = true
          } else {
            dvIsTrailingZeros &= lastRemovedDigit == 0
            lastRemovedDigit = (dv % 10).toInt
            dp /= 10
            dv /= 10
            dm /= 10
            removed += 1
          }
        }
      }

      if (dvIsTrailingZeros && (lastRemovedDigit == 5) && (dv % 2 == 0)) {
        // Round even if the exact numbers is .....50..0.
        lastRemovedDigit = 4
      }
      output = dv +
        (if ((dv == dm &&
               !(dmIsTrailingZeros && roundingMode.acceptLowerBound(even))) ||
             (lastRemovedDigit >= 5)) 1
         else 0)
    } else {
      var done = false // workaround break in .java source
      while ((dp / 10 > dm / 10) && !done) {
        if ((dp < 100) && scientificNotation) {
          // Double.toString semantics requires printing at least two digits.
          done = true
        } else {
          lastRemovedDigit = (dv % 10).toInt
          dp /= 10
          dv /= 10
          dm /= 10
          removed += 1
        }
      }
      output = dv +
        (if ((dv == dm || (lastRemovedDigit >= 5))) 1 else 0)
    }
    val olength = vplength - removed

    // Step 5: Print the decimal representation.
    // We follow Double.toString semantics here.
    var index = offset
    if (sign) {
      result(index) = '-'
      index += 1
    }

    // Values in the interval [1E-3, 1E7) are special.
    if (scientificNotation) {
      var i = 0
      while (i < olength - 1) {
        val c = (output % 10).toInt
        output /= 10
        result(index + olength - i) = ('0' + c).toChar
        i += 1
      }
      result(index) = ('0' + output % 10).toChar
      result(index + 1) = '.'
      index += olength + 1
      if (olength == 1) {
        result(index) = '0'
        index += 1
      }

      // Print 'E', the exponent sign, and the exponent, which has at most three digits.
      result(index) = 'E'
      index += 1
      if (exp < 0) {
        result(index) = '-'
        index += 1
        exp = -exp
      }
      if (exp >= 100) {
        result(index) = ('0' + exp / 100).toChar
        index += 1
        exp %= 100
        result(index) = ('0' + exp / 10).toChar
        index += 1
      } else if (exp >= 10) {
        result(index) = ('0' + exp / 10).toChar
        index += 1
      }
      result(index) = ('0' + exp % 10).toChar
      index += 1
    } else {
      // Otherwise follow the Java spec for values in the interval [1E-3, 1E7).
      if (exp < 0) {
        // Decimal dot is before any of the digits.
        result(index) = '0'
        index += 1
        result(index) = '.'
        index += 1

        var i = exp
        while (i < -1) {
          result(index) = '0'
          index += 1
          i += 1
        }

        val current = index
        i = 0
        while (i < olength) {
          result(current + olength - i - 1) = ('0' + output % 10).toChar
          output /= 10
          index += 1
          i += 1
        }
      } else if (exp + 1 >= olength) {
        var i = 0
        while (i < olength) {
          result(index + olength - i - 1) = ('0' + output % 10).toChar
          output /= 10
          i += 1
        }
        index += olength
        i = olength
        while (i <= exp) {
          result(index) = '0'
          index += 1
          i += 1
        }
        result(index) = '.'
        index += 1
        result(index) = '0'
        index += 1
      } else {
        // Decimal dot is somewhere between the digits.
        var current = index + 1
        var i = 0
        while (i < olength) {
          if (olength - i - 1 == exp) {
            result(current + olength - i - 1) = '.'
            current -= 1
          }
          result(current + olength - i - 1) = ('0' + output % 10).toChar
          output /= 10
          i += 1
        }
        index += olength + 1
      }
    }

    index
  }

  private def pow5bits(e: Int): Int = ((e * 1217359) >>> 19) + 1

  private def decimalLength(v: Long): Int = {
    if (v >= 1000000000000000000L) return 19
    if (v >= 100000000000000000L) return 18
    if (v >= 10000000000000000L) return 17
    if (v >= 1000000000000000L) return 16
    if (v >= 100000000000000L) return 15
    if (v >= 10000000000000L) return 14
    if (v >= 1000000000000L) return 13
    if (v >= 100000000000L) return 12
    if (v >= 10000000000L) return 11
    if (v >= 1000000000L) return 10
    if (v >= 100000000L) return 9
    if (v >= 10000000L) return 8
    if (v >= 1000000L) return 7
    if (v >= 100000L) return 6
    if (v >= 10000L) return 5
    if (v >= 1000L) return 4
    if (v >= 100L) return 3
    if (v >= 10L) return 2
    1
  }

  private def multipleOfPowerOf5(value: Long, q: Int): Boolean =
    pow5Factor(value) >= q

  private def pow5Factor(_value: Long): Int = {
    var value = _value
    // We want to find the largest power of 5 that divides value.
    if ((value % 5) != 0) return 0
    if ((value % 25) != 0) return 1
    if ((value % 125) != 0) return 2
    if ((value % 625) != 0) return 3
    var count = 4
    value /= 625
    while (value > 0) {
      if (value % 5 != 0) {
        return count
      }
      value /= 5
      count += 1
    }
    throw new IllegalArgumentException("" + value)
  }

  /** Compute the high digits of m * 5^p / 10^q = m * 5^(p - q) / 2^q = m * 5^i
   *  / 2^j, with q chosen such that m * 5^i / 2^j has sufficiently many decimal
   *  digits to represent the original floating point number.
   */
  private def mulPow5divPow2(m: Long, i: Int, j: Int) = {
    // m has at most 55 bits.
    val mHigh = m >>> 31
    val mLow = m & 0x7fffffff // 124
    val bits13 = mHigh * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 0) // 93
    val bits03 = mLow * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 0) // 93
    val bits12 = mHigh * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 1) // 62
    val bits02 = mLow * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 1) // 62
    val bits11 = mHigh * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 2) // 31
    val bits01 = mLow * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 2) // 31
    val bits10 = mHigh * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 3) // 0
    val bits00 = mLow * POW5_SPLIT((i * POW5_ARRAY_NCOL) + 3)
    val actualShift = j - 3 * 31 - 21
    if (actualShift < 0) {
      throw new IllegalArgumentException("" + actualShift)
    }
    ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) + bits02 +
      bits11) >>>
      31) +
      bits03 +
      bits12) >>>
      21) +
      (bits13 << 10)) >>>
      actualShift
  }

  /** Compute the high digits of m / 5^i / 2^j such that the result is accurate
   *  to at least 9 decimal digits. i and j are already chosen appropriately.
   */
  private def mulPow5InvDivPow2(m: Long, i: Int, j: Int) = {
    // m has at most 55 bits.
    val mHigh = m >>> 31
    val mLow = m & 0x7fffffff
    val bits13 = mHigh * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 0)
    val bits03 = mLow * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 0)
    val bits12 = mHigh * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 1)
    val bits02 = mLow * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 1)
    val bits11 = mHigh * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 2)
    val bits01 = mLow * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 2)
    val bits10 = mHigh * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 3)
    val bits00 = mLow * POW5_INV_SPLIT((i * POW5_ARRAY_NCOL) + 3)
    val actualShift = j - 3 * 31 - 21
    if (actualShift < 0) {
      throw new IllegalArgumentException("" + actualShift)
    }
    ((((((((bits00 >>> 31) + bits01 + bits10) >>> 31) + bits02 +
      bits11) >>>
      31) +
      bits03 +
      bits12) >>>
      21) +
      (bits13 << 10)) >>>
      actualShift
  }

}

//// RyuGenerateRyuDoubleConstants.scala
////
//// Original RyuDouble.java generated the values for the large POW5_SPLIT
//// and POW5_INV_SPLIT arrays. To improve object creation performance,
//// RyuDouble.scala uses known, fixed constants.
////
//// So that the constants can be easily reproduced, this file
//// documents the origin of the constants and generates the constants
//// themselves be reproduced.
////
//// All output is to the console, which can be redirected on the command
//// line into a file. Such as 'programExecutable > constants.utf-8'.
//
//import java.math.BigInteger
//
//object MainForDouble {
//
//  // Begin - values from  Ryu GitHub RyuDouble.java original.
//
//  final val POS_TABLE_SIZE = 326
//
//  final val NEG_TABLE_SIZE = 291
//
//  final val POW5_BITCOUNT = 121 // max 3*31 = 124
//
//  final val POW5_QUARTER_BITCOUNT = 31
//
//  final val POW5_INV_BITCOUNT = 122 // max 3*31 = 124
//
//  final val POW5_INV_QUARTER_BITCOUNT = 31
//
//  final val mask = BigInteger
//    .valueOf(1)
//    .shiftLeft(POW5_QUARTER_BITCOUNT)
//    .subtract(BigInteger.ONE)
//
//  final val invMask = BigInteger
//    .valueOf(1)
//    .shiftLeft(POW5_INV_QUARTER_BITCOUNT)
//    .subtract(BigInteger.ONE)
//
//  // End - values from  Ryu GitHub RyuDouble.java original.
//
//  final val POW5_ARRAY_NCOL = 4
//
//  private def genEndOfRowComma(currentRow: Int, lastRow: Int): String = {
//    if (currentRow == lastRow) "" else ","
//  }
//
//  private def genSplitValue(pow: BigInteger, pow5Len: Int, j: Int): Int = {
//    pow
//	.shiftRight(
//	  pow5Len - POW5_BITCOUNT
//	    + (3 - j) * POW5_QUARTER_BITCOUNT)
//	.and(mask)
//	.intValue()
//  }
//
//  private def genSplitInvValue(pow: BigInteger,
//				 pow5Len: Int,
//				 j: Int): Int = {
//
//    // We want floor(log_2 5^q) here, which is pow5Len - 1.
//    val flr = pow5Len - 1 + POW5_INV_BITCOUNT
//    val inv = BigInteger.ONE.shiftLeft(flr).divide(pow).add(BigInteger.ONE)
//
//    if (j == 0)
//	inv.shiftRight((3 - j) * POW5_INV_QUARTER_BITCOUNT).intValue()
//    else
//	inv
//	  .shiftRight((3 - j) * POW5_INV_QUARTER_BITCOUNT)
//	  .and(invMask)
//	  .intValue()
//  }
//
//  private def generatePow5ConstantsForDouble(
//	size: Int,
//	arrayName: String,
//	generator: (BigInteger, Int, Int) => Int): Unit = {
//
//    val lastRowIndex = size - 1
//
//    val sb = new StringBuilder(80) // 80 is an arbitrary high guess.
//
//    printf(s"\n  final val $arrayName = scala.Array(\n")
//
//    for (i <- 0 to lastRowIndex) {
//
//	val pow	    = BigInteger.valueOf(5).pow(i)
//	val pow5len = pow.bitLength()
//
//	for (j <- 0 until POW5_ARRAY_NCOL) {
//
//	  val result = generator(pow, pow5len, j)
//
//	  val token = j + 1 match {
//
//	    case 1 => s"      $result, "
//
//	    case POW5_ARRAY_NCOL =>
//	      val eolComma = genEndOfRowComma(i, lastRowIndex)
//	      s"$result$eolComma\n"
//
//	    case _ => s"$result, "
//	  }
//
//	  sb.append(token)
//	}
//
//	print(sb.toString)
//	sb.clear()
//    }
//
//    printf("	  )\n\n")
//  }
//
//  def main(args: Array[String]): Unit = {
//
//    generatePow5ConstantsForDouble(POS_TABLE_SIZE,
//				     "POW5_SPLIT",
//				     genSplitValue)
//
//    generatePow5ConstantsForDouble(NEG_TABLE_SIZE,
//				     "POW5_INV_SPLIT",
//				     genSplitInvValue)
//  }
//
//}
